#pragma once
#include <iostream>
#include "Channel.hpp"
#include <vector>
#include <functional>
#include <unistd.h>
#include <sys/wait.h>

using func_t = std::function<void()>;
using work_t = std::function<void(std::string &)>;

namespace ns_ProcessPool
{
    class ProcessPool
    {
    public:
        ProcessPool(work_t work, std::unordered_map<int, func_t> &func_map, int num) : _work(work), _func_map(func_map), _num(num)
        {
        }
        void InitProcessPool()
        {
            for (int i = 0; i < _num; i++)
            {
                // 创建管道
                int pipefd[2];
                pipe(pipefd);

                pid_t id = fork(); // 子进程是0，父进程是收到子进程的pid

                // 创建子进程，子进程输入重定向到管道读端
                if (id == 0)
                {
                    // 子进程
                    ::close(pipefd[1]);
                    dup2(pipefd[0], 0);
                    // 1.一方面是避免子进程文件描述符xiel
                    // 2.另一方面是使得只有一个fd指向管道写端，只有管道写端全部关闭，读端才能读到0，此时子进程才能正常退出
                    for (auto &channel : channel_list)
                    {
                        int close_fd = channel.FD();
                        ::close(close_fd);
                    }
                    char buffer[1024];
                    int n = read(pipefd[0], buffer, sizeof(buffer) - 1);
                    std::cout << "我接受啦" << std::endl;
                    buffer[n] = 0;
                    std::string channel_name = buffer;
                    // std::cout << buffer << std::endl;
                    // std::cout << channel_name.c_str() << std::endl;

                    _work(channel_name);
                    exit(0);
                }
                ::close(pipefd[0]); // write
                ns_Channel::Channel channel(id, pipefd[1]);
                channel_list.push_back(channel);
                channel.SendName();
                std::cout << "创建管道成功！" << channel_list.back().Name() << std::endl;

                // ns_Channel::Channel channel(id,);
            }
        }

        void DispatcherTask()
        {
            int x = 0;
            int count = 0;
            srand(time(nullptr));
            // 进行派发，就是调用channel，给channel写数据
            while (true)
            {
                int num = rand() % _func_map.size(); // 挑选第几个方法

                std::cout << "主进程开始派发任务: " << std::endl;
                //sleep(1);
                channel_list[x].Send(num);
                x++;
                x %= channel_list.size();
                count++;
                std::cout << "count:" << count << std::endl;
                if (count == 100000)
                {
                    channel_list[x].Send(-1);

                    return;
                }
            }
        }

        // 3.销毁进程池
        void Distory()
        {
            for (auto ch : channel_list)
            {
                ch.Close();
            }

            for (auto ch : channel_list)
            {
                pid_t rid = ::waitpid(ch.ID(), nullptr, 0);
                if (rid > 0)
                {
                    std::cout << "child " << rid << " wait ... success" << std::endl;
                }
            }
        }

        ~ProcessPool()
        {
        }

    private:
        std::vector<ns_Channel::Channel> channel_list; // 记录管道
        work_t _work;
        std::unordered_map<int, func_t> _func_map;
        int _num;
    };
}